home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / PolyPumper 1.4.2 / PolyPumper.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  13.6 KB  |  535 lines  |  [TEXT/CWIE]

  1. /* ----------------------------------------------------------------------
  2.  
  3.     PolyPumper 1.4.2
  4.     
  5.     This snippet demonstrates some drawing techniques. It displays a
  6.     bunch of colorful polygons in a window. It is based in part on
  7.     SplatMaster by Jon Benton.
  8.  
  9.     Written by: Ken Long
  10.     Updated for CW9 by: Paul Celestin
  11.     
  12.     950711 - 1.0.1 - ported to CW
  13.     951201 - 1.0.2 - updated for CW7
  14.     960707 - 1.0.3 - updated for CW9
  15.  
  16. ---------------------------------------------------------------------- */
  17.  
  18. #include <math.h>
  19.  
  20. //• --------------------------------------------------------------- •//
  21.  
  22. #define ourName "\pitty bitty bytes™"
  23. #define keys "\pHit 'K' for Keys."
  24. #define w 0xffff    //• Pseudo white, to save typing.
  25.  
  26. //• --------------------------------------------------------------- •//
  27.  
  28. Boolean singleUs = false;
  29. Boolean finishUs = false;
  30. Boolean framesUs = true;
  31. Boolean blacksUs = false;
  32. Boolean paintsUs = true;
  33. Boolean sticksUs = false;
  34. Boolean undivsUs = true;
  35. Boolean pausesUs = false;
  36. Boolean startsUs = true;
  37. Boolean weBeHued, weBeWaitin;
  38.  
  39. EventRecord theEvent;        
  40.  
  41. Point middle, originalPt, nextPt;
  42. PolyHandle Polly;    //• Grab a hold of Polly!
  43. Rect globWind, ourRect;
  44. PicHandle pict;
  45. Rect pictRect;
  46. WindowPtr pumpWindow;
  47. short lastSpot, radius, radius2, height;
  48. short divisions = 12;        //• Our point total.
  49. long ticks;
  50.  
  51. //• --------------------------------------------------------------- •//
  52.  
  53. void SetForeColor (short red, short green, short blue);
  54. void SetBackColor (short red, short green, short blue);
  55. unsigned short HighLowRandom (unsigned short min, unsigned short max);
  56. short RangeRandom (short range);
  57. void GetDivisions (void);
  58. void GetRadii (void);
  59. void DrawPolygons (void);
  60. void SetUpWindow (void);
  61. void InitManagers (short numMasters);
  62. Boolean CheckTheEquipment (void);
  63. void DoSplash (void);
  64. void SpoutOff (void);
  65. void main (void);
  66.  
  67. //• --------------------------------------------------------------- •//
  68.  
  69. void SetForeColor(short red, short green, short blue)
  70. {
  71.     RGBColor hue;
  72.  
  73.     hue.red = red;
  74.     hue.green = green;
  75.     hue.blue = blue;
  76.  
  77.     RGBForeColor (&hue);
  78. }
  79.  
  80. //• --------------------------------------------------------------- •//
  81.  
  82. void SetBackColor(short red, short green, short blue)
  83. {
  84.     RGBColor hue;
  85.  
  86.     hue.red = red;
  87.     hue.green = green;
  88.     hue.blue = blue;
  89.  
  90.     RGBBackColor (&hue);
  91. }
  92.  
  93. //• --------------------------------------------------------------- •//
  94.  
  95. unsigned short HighLowRandom (unsigned short min, unsigned short max)
  96. {
  97.     unsigned long ranger, tonto;
  98.     unsigned short rawResult;
  99.     
  100.     rawResult = Random ();
  101.     
  102.     if (rawResult < 0)
  103.         rawResult *= -1;
  104.     
  105.     ranger = max - min;
  106.     tonto = (rawResult * ranger) / 65535;
  107.     return (tonto + min);   
  108. }
  109.  
  110. //• --------------------------------------------------------------- •//
  111.  
  112. short RangeRandom (short range)
  113. {
  114.     long rawResult;
  115.  
  116.     rawResult = Random ();
  117.  
  118.     if (rawResult < 0)
  119.         rawResult *= - 1;
  120.     
  121.     return ((rawResult * range) / 32768);
  122. }
  123.  
  124. void GetDivisions ()
  125. {
  126.     //• Total points, inner plus outer.
  127.     //• Anywhere between 0 and 100.
  128.     //• I could have used "HighLowRandom (4, 100);" instead!  :^)
  129.     divisions = RangeRandom(100);
  130.     
  131.     //• Divisions must be even, so I rigged up a phoney "odd"
  132.     //• handler.  If divisions was 9, half of that is 4.5, rounded
  133.     //• up would be 5.
  134.     if (divisions != ceil((divisions / 2) * 2))
  135.         divisions++;
  136. }
  137.  
  138. void GetRadii ()
  139. {
  140.     //• This radius only gets positive values...
  141.     radius = RangeRandom(height);
  142.     
  143.     //• ...but this one gets positive and negative, so the
  144.     //• polygon points can lap, giving the "holey" effect.
  145.     radius2 = HighLowRandom (- height, height);
  146. }
  147.  
  148. //• --------------------------------------------------------------- •//
  149. //• The main action proc, where the magic takes place.
  150. void DrawPolygons ()
  151. {
  152.     short i;
  153.     double thetaStep, theta;
  154.     
  155.     //• Screen center is the start point.
  156.     middle.h = (qd.thePort->portRect.right  / 2);
  157.     middle.v = (qd.thePort->portRect.bottom / 2);
  158.  
  159.     //• The height of our overall draw area.
  160.     height = pumpWindow->portRect.bottom / 2 - 4;
  161.     
  162.     if (! undivsUs)
  163.         GetDivisions ();
  164.  
  165.     //• Less than 4 looks funky.  
  166.     if (divisions < 4)
  167.         divisions = 4;
  168.                     
  169.     if (! sticksUs)
  170.         GetRadii ();
  171.     
  172.     //• Some circle math thing...
  173.     thetaStep = (2 * 3.14159) / divisions;
  174.     theta = 0;
  175.     
  176.     //• Start recording polygon points.
  177.     Polly = OpenPoly ();
  178.     
  179.     //• SetPt handles .h and .v (cool).  Notice no need to
  180.     //• initialize "originalPt" before this?  The values are
  181.     //• calc'd off the already established "radius" value.
  182.     SetPt(&originalPt, radius * cos (theta),
  183.                           radius * sin (theta));
  184.     
  185.     //• Then we move to center, plus that "SetPt" value.
  186.     //• This is a horzontal offset from center, so our polygons
  187.     //• will be "laying on their sides" if half of divisons 
  188.     //• is odd.
  189.     MoveTo(middle.h + originalPt.h, middle.v + originalPt.v);
  190.  
  191.     //• Now that we have a start point, we go from there, around
  192.     //• the circle, for the number of divisions, which we made an 
  193.     //• even total.
  194.     for (i = 0; i < divisions; i++)
  195.     {
  196.         //• But, there are odd and even numbers in the sequence.
  197.         //• We want odd to be one radius and even to be the other.
  198.         //• So we jockey back and forth using the index as a guide.
  199.         if (i == ceil (i / 2) * 2)
  200.             SetPt(&nextPt, radius * cos (theta),
  201.                            radius * sin (theta));
  202.         else
  203.             SetPt(&nextPt, radius2 * cos (theta),
  204.                            radius2 * sin (theta));
  205.                            
  206.         //• Some other circle/math thing.  How far around?
  207.         theta += thetaStep;
  208.         
  209.         //• Still in our loop, we record where the poly point
  210.         //• is, off the center, to the point we just set.
  211.         LineTo(middle.h + nextPt.h, middle.v + nextPt.v);
  212.     }
  213.     //• Finally, we close the polygon with a line back to the
  214.     //• point we started at.
  215.     LineTo(middle.h + originalPt.h, middle.v + originalPt.v);
  216.     
  217.     //• Then stop recording.
  218.     ClosePoly ();
  219.     
  220.     //• Now set a color to paint the polygon with, and paint it
  221.     //• *IF* we're painting.
  222.     if (paintsUs == true)
  223.     {
  224.         SetForeColor (Random (), Random (), Random ());
  225.         PaintPoly (Polly);
  226.     }
  227.     
  228.     //• Then set the forecolor to black for the frame 
  229.     //• *IF* we're framing.
  230.     if (framesUs == true)
  231.     {
  232.         SetForeColor (0, 0, 0);
  233.         FramePoly (Polly);
  234.     }
  235.     
  236.     //• Now dump all the memory this took, 
  237.     //• since the pixels are now ON the screen!
  238.     KillPoly (Polly);
  239. }
  240.  
  241. //• --------------------------------------------------------------- •//
  242. //• "Cheapo" window, but it works!  Set to srceen edges.
  243. void SetUpWindow (void)
  244. {
  245.     HideMenuBar ();            //• Do this while we're here.
  246.     pumpWindow = NewCWindow (0L, &qd.screenBits.bounds, "\p", true, 
  247.                             plainDBox, (WindowPtr) -1L, true, 0);
  248.     SetPort (pumpWindow);
  249.     HideCursor ();            //• Swat the fly, too.
  250.     DoSplash ();            //• Do some heavy bragging.
  251. }
  252.  
  253. //• --------------------------------------------------------------- •//
  254.  
  255. void InitManagers (short numMasters)
  256. {
  257.     short i;            
  258.                                 //• The manager's names:
  259.     InitGraf (&qd.thePort);        //• Quick Draw McGraw.
  260.     InitFonts ();                //• Alfonso
  261.     InitWindows ();                //• Windex.
  262.     TEInit ();                    //• Te he he.
  263.     InitDialogs (((void *) 0));    //• Paul Bunion (lumberjack).
  264.     
  265.     for (i = 0; i < 5; i++)
  266.     {
  267.         MoreMasters ();            
  268.     }
  269.     FlushEvents (everyEvent, 0);
  270.     InitCursor ();                //• Watch your language!
  271. }
  272.  
  273. //• --------------------------------------------------------------- •//
  274. //• A hold-over from where I got it (SplatMaster).
  275. //• Mainly check for color is what we want.
  276. Boolean CheckTheEquipment (void)
  277. {
  278.     #define versRequested         1        //• This is a 68000
  279.     #define The_Wait_Trap     0x60
  280.     #define Unimpl_Pimple     0x9f
  281.  
  282.     OSErr err;
  283.     SysEnvRec theWorld;                //• Wrecking the world?
  284.     Boolean runability = false;        //• Got legs?
  285.  
  286.     weBeHued = false;
  287.  
  288.     err = SysEnvirons(versRequested, &theWorld);
  289.  
  290.     //• Fi this is a 68000 Mac, we skip to _L99 with runability false.
  291.     if (err != noErr)
  292.         goto _L99;        //• The dreaded "goto."  Actually useful.
  293.  
  294.     //• If there was no error in the "noErr", we read this.
  295.     //• _L99, runability still false, on a MacSE.
  296.     if (theWorld.machineType <= 3)
  297.         goto _L99;
  298.  
  299.     //• If the machineType was okay, we read this.
  300.     if (theWorld.hasColorQD)
  301.         weBeHued = true;            //• Huey To-us and the News!
  302.  
  303.     //• If we made it this far...
  304.     runability = true;                //• Doesn't apply to Ross Perot.
  305.     
  306.     //• Why do this?  We're using "GetNextEvent!"  Leftovers.
  307.     weBeWaitin = (NGetTrapAddress(The_Wait_Trap, ToolTrap) !=
  308.                   NGetTrapAddress(Unimpl_Pimple, ToolTrap));
  309.  
  310. _L99:
  311.     if (runability)
  312.         return true;
  313. }
  314.  
  315. //• --------------------------------------------------------------- •//
  316. void DoSplash ()        //• Much ado over nothing!
  317. {
  318.     short pR, pB, sR, sB, L, T, R, B;    //• Some stuff to save typing
  319.                                         //• in our SetRect call :^)
  320.     pict = GetPicture (128);
  321.  
  322.     if (pict != 0L)
  323.     {
  324.         pR = (**pict).picFrame.right;
  325.         pB = (**pict).picFrame.bottom;
  326.         sR = pumpWindow->portRect.right; 
  327.         sB = pumpWindow->portRect.bottom;
  328.         L = sR / 2 - pR / 2;
  329.         T = sB / 2 - pB / 2;
  330.         R = L + pR;
  331.         B = T + pB;
  332.         SetRect (&pictRect, L, T, R, B);
  333.         DrawPicture (pict, &pictRect);
  334.         ReleaseResource ((Handle) pict);
  335.     }
  336.     while (! Button ())        //• If we ain't clickin'...
  337.         ;                    //• we keeps on stickin'!
  338.     
  339.     EraseRect (&pictRect);
  340.     if (startsUs)
  341.     {
  342.         DoInstructions ();
  343.         startsUs = false;
  344.     }
  345.     SpoutOff ();            //• Put this up, initially.
  346. }
  347.  
  348. //• --------------------------------------------------------------- •//
  349. DoInstructions ()
  350. {
  351.     pict = GetPicture (129);
  352.      EraseRect (&pumpWindow->portRect);
  353.      
  354.     if (pict != 0L)
  355.     {
  356.          DrawPicture (pict, &pictRect);
  357.         ReleaseResource ((Handle) pict);
  358.     }
  359.     while (! Button ())        //• If we ain't clickin'...
  360.         ;                    //• we keeps on stickin'!
  361.     EraseRect (&pictRect);
  362.     SpoutOff ();
  363. }    
  364.     
  365. //     Str255 s00 = "\pSINGLE KEY CONTROLS:",
  366. //            s01 = "\p+........Increase divisions by two.",
  367. //            s02 = "\p-........Decrease divisions by two.",
  368. //            s03 = "\p*........Pause or not.",
  369. //            s04 = "\pB........White or black background.",
  370. //            s05 = "\pD........Divisons random or not.",
  371. //            s06 = "\pE........Erase window once.",
  372. //            s07 = "\pF........Frame polygon or not.",
  373. //            s08 = "\pI........Show these instructions again.",
  374. //            s09 = "\pP........Paint polygon or not.",
  375. //            s10 = "\pR........Radii random or not.",
  376. //            s11 = "\pS........Erase window after 1 second delay, or not.",
  377. //            s12 = "\pQ........Quit.",
  378. //            s13 = "\pCLICK TO EXIT INSTRUCTIONS";
  379. //     
  380. //     //• Wipe the slate and put up instructions.
  381. //     EraseRect (&pumpWindow->portRect);
  382. //     Delay (20L, &ticks);
  383. //     MoveTo (20,  40); DrawString (s00);
  384. //     MoveTo (20,  60); DrawString (s01);
  385. //     MoveTo (20,  80); DrawString (s02);
  386. //     MoveTo (20, 100); DrawString (s03);
  387. //     MoveTo (20, 120); DrawString (s04);
  388. //     MoveTo (20, 140); DrawString (s05);
  389. //     MoveTo (20, 160); DrawString (s06);
  390. //     MoveTo (20, 180); DrawString (s07);
  391. //     MoveTo (20, 200); DrawString (s08);
  392. //     MoveTo (20, 220); DrawString (s09);
  393. //     MoveTo (20, 240); DrawString (s10);
  394. //     MoveTo (20, 260); DrawString (s11);
  395. //     MoveTo (20, 280); DrawString (s12);
  396. //     MoveTo (20, 320); DrawString (s13);
  397. //     while (! Button ())
  398. //         ;
  399. //     //• Wipe the slate and on with the show!
  400. //     EraseRect (&pumpWindow->portRect);
  401. //}
  402.  
  403. //• --------------------------------------------------------------- •//
  404. //• Brag a little, and let user know how to get out, etc.
  405. void SpoutOff ()
  406. {
  407.     SetForeColor (w / 2, w / 2, w / 2);
  408.     
  409.     MoveTo (5, pumpWindow->portRect.bottom - 5);
  410.     DrawString (keys);
  411.     MoveTo (pumpWindow->portRect.right - StringWidth (ourName) - 5, 
  412.             pumpWindow->portRect.bottom - 5);
  413.     DrawString (ourName);
  414. }        
  415.         
  416. //• --------------------------------------------------------------- •//
  417.  
  418. void main ()
  419. {
  420.     short chCode;
  421.     char theKey;
  422.     unsigned long myRand = qd.randSeed;
  423.     
  424.     GetDateTime (&myRand);
  425.     
  426.     InitManagers (5);
  427.     if (CheckTheEquipment())     //• Find out about our environment.
  428.     {
  429.         SetUpWindow ();
  430.         do
  431.         {
  432.             if (GetNextEvent(everyEvent, &theEvent))
  433.                 switch (theEvent.what)
  434.                 {
  435.                     case keyDown:
  436.                         chCode = (theEvent.message & charCodeMask);
  437.                         //• These key hits are self explanatory.
  438.                         switch (chCode)
  439.                         {
  440.                             case 'b':
  441.                                 if (blacksUs == false)
  442.                                 {
  443.                                     SetBackColor (w, w, w);
  444.                                     EraseRect (&pumpWindow->portRect);
  445.                                 }
  446.                                 else
  447.                                 {
  448.                                     SetBackColor (0, 0, 0);
  449.                                     EraseRect (&pumpWindow->portRect);
  450.                                 }
  451.                                 SpoutOff ();
  452.                                 blacksUs = ! blacksUs;
  453.                             break;
  454.                             
  455.                             case 'd':
  456.                                 undivsUs = ! undivsUs;
  457.                             break;
  458.                             
  459.                             case 'a':            //• Wipe.
  460.                                 EraseRect (&pumpWindow->portRect);
  461.                                 DoSplash ();    //• Put this back.
  462.                             break;
  463.                             
  464.                             case 'c':            //• Wipe.
  465.                                 EraseRect (&pumpWindow->portRect);
  466.                                 SpoutOff ();    //• Put this back.
  467.                             break;
  468.                             
  469.                             case 'f':
  470.                                 framesUs = ! framesUs;
  471.                             break;
  472.  
  473.                             case 'k':
  474.                                 DoInstructions ();
  475.                                 //• Flush in case user hit 'i' again.
  476.                                 FlushEvents (everyEvent, 0);
  477.                                 SpoutOff ();
  478.                             break;
  479.  
  480.                             case 'p':
  481.                                 paintsUs = ! paintsUs;
  482.                             break;
  483.                             
  484.                             case 'q':
  485.                                 finishUs = true;
  486.                             break;
  487.                             
  488.                             case 'r':
  489.                                 sticksUs = ! sticksUs;
  490.                             break;
  491.                             
  492.                             case 's':
  493.                                 singleUs = ! singleUs;
  494.                             break;
  495.  
  496.                             case '+':
  497.                                 divisions += 2;
  498.                             break;
  499.  
  500.                             case '-':
  501.                                 divisions -= 2;
  502.                             break;
  503.  
  504.                             case '*':
  505.                                 pausesUs = ! pausesUs;
  506.                             break;
  507.                         }
  508.                     break;
  509.                     
  510.                     //• It does this every time, unless something
  511.                     //• changes.
  512.                     default:
  513.                         //• Do this *IF* single is true and
  514.                         //• pausing is false.
  515.                         if ((singleUs) && (! pausesUs))
  516.                         {
  517.                             DrawPolygons ();
  518.                             Delay (59L, &ticks);
  519.                             EraseRect (&pumpWindow->portRect);
  520.                             SpoutOff ();
  521.                         }
  522.                         //• Otherwise just draw, unless paused.
  523.                         if ((! singleUs) && (! pausesUs))
  524.                             DrawPolygons ();
  525.                     break;
  526.                 }
  527.         }while (! finishUs);    //• 'q' key sets us free.
  528.     }
  529.     ShowMenuBar ();        //• This would probably happen anyway, but...
  530.     InitCursor ();
  531. }
  532.  
  533. //• --------------------------------------------------------------- •//
  534.  
  535. //• We're outta here!